feat(sdk): Flatten the hierarchy of caches in the Event Cache, part 2: Pinned events#6568
Merged
Conversation
This patch renames `PinnedEventCache` to `PinnedEventsCache` (and same for all types having `PinnedEventCache` as a prefix). Why? Because it's a cache about _pinned-events_, not a single _pinned-event_ :-).
…`Room`. This patch changes `PinnedEventsCache::new` to receive a `WeakRoom` instead of a `Room`. It then returns a `Result<Self>`, with `Err` if the `WeakRoom` doesn't point to the `Room` anymore. Thus, this patch changes `get_or_init` by `get_or_try_init`, but this one is unstable. So this patch switches from `OnceLock` to `OnceCell`, which provides a stable one. Why this change? Because in a later refactoring, providing a `Room` is a bit annoying: all we will have is a `WeakRoom`. We could do this work of upgrading the `WeakRoom` to a `Room`, but it seems akward as all caches are holding a `WeakRoom` if room is necessary.
96078c6 to
c1aad24
Compare
14 tasks
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## features/event-cache-refactoring #6568 +/- ##
====================================================================
- Coverage 89.87% 89.84% -0.04%
====================================================================
Files 383 384 +1
Lines 107846 107967 +121
Branches 107846 107967 +121
====================================================================
+ Hits 96929 97001 +72
- Misses 7225 7270 +45
- Partials 3692 3696 +4 ☔ View full report in Codecov by Sentry. |
…entsCacheState`. This patch renames `PinnedEventsCacheStateLock` to `LockedPinnedEventsCacheState` to match other namings in `RoomEventCache` and `ThreadEventCache` for the sake of consistency.
Merging this PR will improve performance by 48.88%
Performance Changes
Tip Curious why this is faster? Comment Comparing Footnotes |
73fa63f to
41ce2bb
Compare
This patch introduces the new type `PinnedEventsCacheUpdateSender` _à la_ `ThreadEventCacheUpdateSender` or `RoomEventCacheUpdateSender`. It abstracts the channels to send updates about. Yes, for the moment, it has a single channel, but it's better to provide the same abstractions for all caches.
This patch introduces the `PinnedEventsCacheInner` type that is used inside `PinnedEventsCache` to make it cheap to clone. It was already the case before with all the fields beind `Arc<_>` but we are about to move data in their correct place, and thus it will add more `Arc<_>`, which is not good. Let's adopt the same patterns as the other caches too for the sake of consistency.
This patch adds `PinnedEventsCacheInner::update_sender`, making `PinnedEventsCacheState::update_sender` a clone of the former. This is going to be useful in the next commit for handling pinned-events in `ResetCaches`.
This patch adds `EventCache::pinned_events` to get the `PinnedEventsCache`. This patch adds `Caches::pinned_events`. `ResetCaches` also handle the pinned-events cache. To make it works, this patch adds `PinnedEventsCache::state`, `PinnedEventsCache::update_sender` and `PinnedEventsCacheStateLockWriteGuard::reset`. This one is new as the feature wasn't implemented before!
This patch adds the pipeline for `PinnedEventsCache` via `aggregator_timeline_for_pinned_events`.
…stead of `RoomEventCache`. This patch moves `maybe_add_live_related_events` to `handle_timeline`. `handle_timeline` is called by `handle_(joined|left)_room_update`, which are themselves called by `Caches`. This patch also removes other methods used by `maybe_add_live_related_events` but are no longer useful since we have the aggregator, namely `extract_relation_target` and `extract_redaction_target`. Finally, this patch removes the call to `maybe_add_live_related_events` in `RoomEventCacheStateLockWriteGuard::post_process_new_events`, which removes the need to acquire a write lock over the room' state here.
This patch runs the `filter_duplicate_events` function inside `handle_sync` to deduplicate events related to pinned events.
This patch applies event redactions over pinned events.
…he`.
This patch updates `TimelineFocusKind::PinnedEvents { event_cache }` to
use a `PinnedEventsCache` instead of a `RoomEventCache`.
This patch removes `subscribe_to_pinned_events`, it is now useless.
…ving `RoomEventCache`. This patch updates R2D2 to fetch the `PinnedEventsCache` from `EventCache` without using `RoomEventCache`.
This patch removes deadcode about `PinnedEventsCache` in `RoomEventCache`.
41ce2bb to
42fef16
Compare
poljar
approved these changes
May 21, 2026
Contributor
poljar
left a comment
There was a problem hiding this comment.
I left a couple of nits/questions.
The rest of this looks good to me.
b62812a
into
matrix-org:features/event-cache-refactoring
61 checks passed
2 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR is the sequel of #6517. This time, we are “flattening” the pinned-events cache, i.e. it extracts the pinned-event cache from the room cache to move it directly in
Caches. The tree goes from:graph TD; EventCache-->Caches; Caches-->RoomEventCache; RoomEventCache-->RoomEventCacheState; RoomEventCacheState-->PinnedEventCache; PinnedEventCache-->PinnedEventCacheState;to:
graph TD; EventCache-->Caches; Caches-->RoomEventCache; Caches-->PinnedEventsCache; RoomEventCache-->RoomEventCacheState; PinnedEventsCache-->PinnedEventsCacheState;Breaking Changes
First and foremost,
PinnedEventCacheis renamedPinnedEventsCache(plural form onEvent) because it contains… multiple… events… hence the plural.All methods related to pinned-events on
RoomEventCacheare removed, for example:RoomEventCache::subscribe_to_pinned_events(side note: funny how we have the plural here 🤪) is nowPinnedEventsCache::subscribe.EventCachenow provides 1 new public method:pinned_eventsto lazily access to thePinnedEventsCache.New Features or Bug Fixes
Because, yeah, we have new features coming with this refactoring!
extract_relationhelper introduced in the previous PR. This is part of the newaggregator::aggregate_timeline_for_pinned_eventspipeline!deduplicatormodule!EventCacheStoreuses a single table for all the events, when the room cache was redacting an event, it was redacted for all the caches. Solid, good, except the pinned-events cache had an unredacted event in memory! Every in-memory modification is broadcasted to the database, but the opposite direction is not supported. Now, redactions are handled like any other caches, both in-memory and in-database. (Note: all these features will be refactored to be shared by all the caches once the “flattening” is over).Known Caveats
Sync gaps are not resolved. This was already the case before, and it's not fixed here, but at least it makes it obvious by looking at the code. There is no pagination whatsoever with the pinned-events cache.
How do we resolve that? When the cache loads, for each pinned-event,
/relationsis called to fetch all its related events. It is efficient except that once the pinned-event cache is created, it stays in memory for the entire lifetime of theClient.It means that if the pinned-events cache is loaded, then a couple of sync happens, no missing events, good, then a gappy sync: ha, too bad, maybe an event related to a pinned-event is missing.
Solution 1: Generalise the “shriking when no more subscribers” mechanism we have for the room cache, and extend that on the pinned-events cache so that we can reload its state from the network.
Solution 2: When the pinned-events cache detects a gap in the sync (now it's easy, it has its own
handle_syncmethod), we must reset its state by relying on the network only. I personally prefer this solution. A bit bazooka for a fly, but it will be the most reliable for the moment.Thoughts?
CHANGELOG.mdfiles.